<?php
/**
 * Abstract class operations base.
 * Will be used as parent by different DB operations such as select etc
 *
 */

abstract class operationsBase
{
    // DB
    protected $dbTypes  = false;
    protected $database = false;
    protected $dbObject = false;
    // Operation
    protected $tableName    = false;
    protected $killChaining = false;
    protected $lastError    = false;
    protected $filter       = false;
    protected $auxTypes     = array();

    public function __construct(&$dbTypes, $database, &$dbObject)
    {
        $this->dbTypes  = $dbTypes;
        $this->database = $database;
        $this->dbObject = $dbObject;
        return $this;
    }

    protected function _from($tableName, $database = false)
    {
        if ($this->killChaining) return $this;
        $database = (empty($database))?$this->database:$database;
        if (empty($this->dbTypes[$database][$tableName]))
        {
            $this->killChaining = true;
            $this->lastError    = "$tableName does not exist";
        }
        else
        {
            $this->tableName = $tableName;
        }
        return $this;
    }

    public function where($left, $middle = false, $root = false)
    {
        // Check kill
        if ($this->killChaining) return $this;
        // Check if is already build filter
        if (empty($middle) && empty($root) && (is_a($left, 'dbFilter')))
        {
            $filter = $this->parseFilter($left);
            $this->filter = $filter;
        }
        else
        {
            if (!empty($middle) && !empty($root))
            {
                // Start building filter
                $filter = filter($left, $middle, $root);
                $filter = $this->parseFilter($filter);
                $this->filter = $filter;
            }
            else
            {
                $this->killChaining = true;
                $this->lastError    = "wrong filters";
            }
        }
        // Return self
        return $this;
    }

    protected function parseFilter($filter, $fromHaving = false)
    {
        if (is_a($filter, 'dbFilter'))
        {
            $left   = $filter->left;
            $middle = $filter->middle;
            $right  = $filter->right;
            // Parse recursively left
            $combination = false;
            if ((!is_a($left, 'dbFilter')) && ((!is_a($right, 'dbFilter'))))
            {
                $middle = $this->validateMiddle($middle);
                if ($middle == 'IN')
                {
                    if (is_array($right))
                    {
                        $res = true;
                        $vals = array();
                        foreach ($right as $auxRight)
                        {
                            $this->validateFieldNameAndValue($left, $auxRight);
                            if (($auxRight && ($auxRight != 'NULL')) && $res)
                            {
                                $vals[]=$auxRight;
                            }
                            else
                            {
                                $res = false;
                            }
                        }
                        if ($res)
                        {
                            $right = '('.implode(',', $vals).')';
                        }
                        else
                        {
                            $right = 'NULL';
                        }
                    }
                    else
                    {
                        $this->validateFieldNameAndValue($left, $right);
                    }
                }
                else
                {
                    $this->validateFieldNameAndValue($left, $right, $fromHaving);
                }
            }
            else if ((is_a($left, 'dbFilter')) && ((is_a($right, 'dbFilter'))))
            {
                $left   = $this->parseFilter($left);
                $right  = $this->parseFilter($right);
                $middle = $this->validateMiddle($middle, true);
            }
            if (($left !== false) && ($middle !== false) && ($right !== false))
            {
                return "($left $middle $right)";
            }
            else
            {
                return '';
            }
        }
        else
        {
            return '';
        }
    }

    protected function validateFieldNameAndValue(&$fieldName, &$fieldValue, $fromHaving = false)
    {
        $field = $this->getTableAndField($fieldName);
        if (!empty($field))
        {
            $table = ($field['table'] == '')?$this->tableName:$field['table'];
            if (!empty($this->auxTypes[$table]))
            {
                $auxTable = $table;
                $table    = $this->auxTypes[$table];
            }
            if (is_a($fieldValue, 'SubSelect'))
            {
                if (!empty($auxTable))
                {
                    $fieldName = $auxTable.'.'.$field['field'];
                }
                else
                {
                    $fieldName = $table.'.'.$field['field'];
                }
                $fieldValue = $fieldValue->rawSql;
            }
            else
            {
                if (!empty($this->dbTypes[$this->database][$table][$field['field']]))
                {
                    // Check if it's actually a join
                    $possibleField = $this->getTableAndField($fieldValue);
                    $table2 = ($possibleField['table'] == '')?$this->tableName:$possibleField['table'];
                    if (!empty($this->auxTypes[$table2]))
                    {
                        $auxTable2 = $table2;
                        $table2    = $this->auxTypes[$table2];
                    }
                    if (!empty($this->dbTypes[$this->database][$table2][$possibleField['field']]))
                    {
                        if (!empty($auxTable))
                        {
                            $fieldName = $auxTable.'.'.$field['field'];
                        }
                        else
                        {
                            $fieldName = $table.'.'.$field['field'];
                        }
                        if (!empty($auxTable2))
                        {
                            $fieldValue = $auxTable2.'.'.$possibleField['field'];
                        }
                        else
                        {
                            $fieldValue = $table2.'.'.$possibleField['field'];
                        }
                    }
                    else
                    {
                        $type = $this->dbTypes[$this->database][$table][$field['field']];
                        if ($type == FIELD_TYPE_STRING)
                        {
                            $fieldValue = strip_tags($fieldValue);
                            if (!empty($fieldValue))
                            {
                                $fieldValue = "'".$this->dbObject->escape($fieldValue)."'";
                            }
                            else
                            {
                                $fieldValue = "''";
                            }
                        }
                        else if ($type == FIELD_TYPE_FLOAT)
                        {
                            $fieldValue = floatval($fieldValue);
                        }
                        else if ($type == FIELD_TYPE_INTEGER)
                        {
                            if (!is_numeric($fieldValue))
                            {
                                $fieldValue = 'NULL';
                            }
                            else
                            {
                                $fieldValue = intval($fieldValue);
                            }
                        }
                        if (!empty($auxTable))
                        {
                            $fieldName = $auxTable.'.'.$field['field'];
                        }
                        else
                        {
                            $fieldName = $table.'.'.$field['field'];
                        }
                    }
                }
                else
                {
                    if ($fromHaving)
                    {
                        $havingField = false;
                        foreach ($this->fieldList as $fieldInfo)
                        {
                            if (isset($fieldInfo['alias']) && ($fieldInfo['alias'] == $fieldName) && isset($fieldInfo['operation']) && (($fieldInfo['operation'] == 'COUNT') || ($fieldInfo['operation'] == 'SUM') || ($fieldInfo['operation'] == 'MAX')))
                            {
                                $havingField = true;
                                break;
                            }
                        }
                        if ($havingField)
                        {
                            if (!is_numeric($fieldValue))
                            {
                                $fieldValue = 'NULL';
                            }
                            else
                            {
                                $fieldValue = intval($fieldValue);
                            }
                        }
                        else
                        {
                            $fieldName  = false;
                            $fieldValue = false;
                        }
                    }
                    else
                    {
                        $fieldName  = false;
                        $fieldValue = false;
                    }
                }                
            }
        }
        else
        {
            $fieldName  = false;
            $fieldValue = false;
        }
    }

    protected function validateMiddle($middle, $logical = false)
    {
        $middle   = strtoupper(trim($middle));
        $middleOk = false;
        switch($middle)
        {
            case '=':
                $middleOk = true;
                break;
            case '<>':
                $middleOk = true;
                break;
            case '>':
                $middleOk = true;
                break;
            case '>=':
                $middleOk = true;
                break;
            case '<=':
                $middleOk = true;
                break;
            case '<':
                $middleOk = true;
                break;
            case '&':
                $middleOk = true;
                break;
            case '|':
                $middleOk = true;
                break;
            case 'IN':
                $middleOk = true;
                break;
            case 'IS':
                $middleOk = true;
                break;
            case 'IS NOT':
                $middleOk = true;
                break;
        }
        if ($logical)
        {
            switch($middle)
            {
                case 'AND':
                    $middleOk = true;
                    break;
                case 'OR':
                    $middleOk = true;
                    break;
            }
        }
        if ($middleOk)
        {
            return $middle;
        }
        else
        {
            return false;
        }
    }

    protected function getTableAndField($field)
    {
        // Specified table
        if (($dotPosition = strpos($field, '.')) !== false)
        {
            $table = substr($field,0,$dotPosition);
            $field = substr($field,$dotPosition+1);
        }
        // Default table
        else
        {
            $table = '';
            $field = $field;
        }
        if ($field != '')
        {
            // Now check alias (only works when is done line field AS alias)
            if ((($aliasPos = strpos($field, ' as')) !== false) && ($field != '*'))
            {
                $fieldName = substr($field, 0, $aliasPos);
                $alias     = trim(str_replace(' as', '', substr($field, $aliasPos)));
                return array('table' => $table, 'field' => $fieldName, 'alias' => $alias);
            }
            else
            {
                return array('table' => $table, 'field' => $field);
            }
        }
        else
        {
            return false;
        }
    }

}
?>